/** * AbstractListValueHolder - A partial implementation of a ListValueHolder Interface * * Copyright (c) 2002 * Marty Phelan, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.taursys.model; import javax.swing.event.*; import java.util.*; import com.taursys.model.event.*; import com.taursys.swing.*; /** * AbstractListValueHolder is a partial implementation of a ListValueHolder Interface. * @author Marty Phelan * @version 1.0 */ public class AbstractListValueHolder extends AbstractCollectionValueHolder implements ListValueHolder { private int position = -1; private transient Vector listSelectionListeners; private boolean ignoreReset = false; private Comparator comparator; /** * Constructs a new AbstractListValueHolder */ public AbstractListValueHolder(ObjectValueHolder holder) { super(holder); } /** * Constructs a new AbstractListValueHolder */ public AbstractListValueHolder(ObjectValueHolder holder, List list) { super(holder, list); } /** * Indicates whether there is another (any) Objects in the List. */ public boolean hasNext() { return (position+1) < size(); } /** * Indicates whether there is a prior Object in the List. */ public boolean hasPrior() { return position > 0; } /** * Indicates if the List has any Objects. */ public boolean hasAny() { return size() > 0; } /** * Gets the current position in the list. Returns -1 if position invalid. */ public int getPosition() { return position; } /** * Gets the current number of rows in the list. */ public int getRowCount() { return size(); } /** * Makes the given row number the current available object. You should first * invoke getRowCount to ensure that you are not requesting a row out of range. */ public void moveTo(int row) { getObjectValueHolder().setObject(getList().get(row)); position = row; fireValueChanged(); } /** * Makes the last object in the List available. You should first invoke the * hasAny to ensure that there is an object in the List. * If the list is empty, the current object will be null. */ public void first() { if (hasAny()) { moveTo(0); } else { reset(); } } /** * Makes the next object in the List available. You should invoke * the hasNext method BEFORE invoking this method to ensure that there IS * a next object. */ public void next() { position++; getObjectValueHolder().setObject(getList().get(position)); fireValueChanged(); } /** * Makes the prior object in the List available. You should first invoke the * hasPrior to ensure that there is a prior object in the List. */ public void prior() { position--; getObjectValueHolder().setObject(getList().get(position)); fireValueChanged(); } /** * Makes the last object in the List available. You should first invoke the * hasAny to ensure that there is an object in the List. * If the list is empty, the current object will be null. */ public void last() { if (hasAny()) { moveTo(size() - 1); } else { reset(); } } /** * Resets this holder so that you can iterate the List from the beginning. */ public void reset() { if (!ignoreReset) { position = -1; getObjectValueHolder().setObject(null); fireValueChanged(); } } /** * Search through the items in the list for a match based on comparing the given properties/values. * @param propertyNames which properties to compare for a match * @param values the values to match * @return the first item in the list which matches the criteria else -1 */ public int indexOf(String[] propertyNames, Object[] values) throws ModelException { if (propertyNames == null || values == null || propertyNames.length != values.length) throw new ModelException(ModelException.REASON_MULTI_PROPERTY_MISMATCH); for (int i = 0; i < size(); i++) { Object[] itemValues = getPropertyValues(propertyNames, i); if (isMatchAll(values, itemValues)) return i; } return -1; } private boolean isMatchAll(Object[] values1, Object[] values2) { for (int i = 0; i < values1.length; i++) { if (!isMatch(values1[i], values2[i])) return false; } return true; } private boolean isMatch(Object value1, Object value2) { if (value1 == null && value2 == null) return true; if (value1 == null) return false; try { return ((Comparable)value1).compareTo(value2) == 0; } catch (ClassCastException ex) { com.taursys.debug.Debug.error( "Property in value object must be Comparable. Object=" + value1); return false; } } /** * Get the values for the given properties in the valueObject at the given index. */ public Object[] getPropertyValues(String[] propertyNames, int index) throws ModelException { return getObjectValueHolder().getPropertyValues( propertyNames, get(index)); } /** * Returns the value of the given property in the valueObject of the given index. */ public Object getPropertyValue(String propertyName, int index) throws ModelException { return getObjectValueHolder().getPropertyValue( propertyName, getList().get(index)); } /** * Set the values for the given properties in the valueObject. * Fires a StateChanged event to any listeners. */ public void setPropertyValues(String[] propertyNames, Object[] values, int index) throws ModelException { getObjectValueHolder().setPropertyValues( propertyNames, values, get(index)); } /** * Sets (replace/copy) the object in the current position. You should ensure * that the current position is valid before invoking this method. Depending * on the specific implementation, the given object may either replace the * current object in the list, or the property values of the given object may * be copied to the current object in the list. */ public void setObject(Object obj) { getObjectValueHolder().setObject(obj); getList().set(position, obj); } /** * Sets the List that this ValueHolder will use and moves to first position (if any). * The list contains the set of Value Objects. * @param newCollection the List that this ValueHolder will use * @throws ClassCastException if given collection is not a List */ public void setCollection(Collection newCollection) { setList((List)newCollection); } /** * Sets the List(collection) that this ValueHolder will use. Sorts the list * by the current comparator (if any), moves to first position (if any) and * broadcasts a ListContentChangeEvent and a ListSelectionEvent. * The list contains the set of ValueObjects. * @param newList the List that this ValueHolder will use */ public void setList(java.util.List newList) { ignoreReset = true; super.setCollection(newList); ignoreReset = false; if (comparator != null) Collections.sort(getList(), comparator); listContentsPositionChange(); } /** * Gets the List that this ValueHolder will use. The list contains the set * of Value Objects. */ public java.util.List getList() { return (List)getCollection(); } /** * Set the Comparator that will be used to sort this List. The list is * sorted whenever you change the list (using setList) or invoke the * sort method. * @param comparator the Comparator used to sort this List. */ public void setComparator(Comparator comparator) { this.comparator = comparator; } /** * Get the Comparator that will be used to sort this List. The list is * sorted whenever you change the list (using setList) or invoke the * sort method. * @return the Comparator used to sort this List. */ public Comparator getComparator() { return comparator; } /** * Sort the list using the current comparator. After sorting, move the position * to the beginning of the list and broadcast a ListContentChangeEvent * and a ListSelectionEvent. No actions occur if the comparator is null. */ public void sort() { if (comparator != null) { Collections.sort(getList(), comparator); listContentsPositionChange(); } } /** * Move to first row in list, select object and broadcast a ListContentChangeEvent * and a ListSelectionEvent. */ private void listContentsPositionChange() { Object vo = null; position = -1; if (getList() != null && size() > 0) { position = 0; vo = getList().get(position); } getObjectValueHolder().setObject( vo, new ListContentChangeEvent(this, vo==null)); fireValueChanged(new ListSelectionEvent(this, position, position, false)); } /** * Remove a listener from the list that's notified each time a change to the selection occurs. * * @param l the ListSelectionListener * @see #addListSelectionListener */ public synchronized void removeListSelectionListener(ListSelectionListener l) { if (listSelectionListeners != null && listSelectionListeners.contains(l)) { Vector v = (Vector) listSelectionListeners.clone(); v.removeElement(l); listSelectionListeners = v; } } /** * Add a listener to the list that's notified each time a change to the selection occurs. * * @param l the ListSelectionListener * @see #removeListSelectionListener */ public synchronized void addListSelectionListener(ListSelectionListener l) { Vector v = listSelectionListeners == null ? new Vector(2) : (Vector) listSelectionListeners.clone(); if (!v.contains(l)) { v.addElement(l); listSelectionListeners = v; } } /** * Notifies all ListSelectionListeners that the position has changed. * It generates a ListselectionEvent with this value holder as the source, * the current position as the first and last index, and false as ValueIsAdjusting. */ protected void fireValueChanged() { fireValueChanged(new ListSelectionEvent(this, position, position, false)); } /** * Notifies all ListSelectionListeners of the given ListSelectionEvent. */ protected void fireValueChanged(ListSelectionEvent e) { if (listSelectionListeners != null) { Vector listeners = listSelectionListeners; int count = listeners.size(); for (int i = 0; i < count; i++) { ((ListSelectionListener) listeners.elementAt(i)).valueChanged(e); } } } // ============================================================ /** * Makes the given row number the current available object. You should first * invoke getRowCount to ensure that you are not requesting a row out of range. */ private void reposition() { if (position >= getList().size()) position = getList().size() - 1; Object vo = null; if (position >= 0) vo = getList().get(position); getObjectValueHolder().setObject( vo, new ListContentChangeEvent(this, vo==null)); fireValueChanged(new ListSelectionEvent(this, position, position, false)); } private void reposition(Object o) { position = getList().indexOf(o); reposition(); } public Object remove() { Object o = getList().remove(position); reposition(); return o; } public Object remove(int index) { Object o = getList().remove(index); reposition(); return o; } public boolean remove(Object o) { boolean b = getList().remove(o); reposition(); return b; } public boolean removeAll(Collection c) { boolean b = getList().removeAll(c); reposition(); return b; } public boolean retainAll(Collection c) { boolean b = getList().retainAll(c); reposition(); return b; } public void clear() { getList().clear(); reposition(); } public boolean add(Object o) { boolean b = getList().add(o); reposition(o); return b; } public void add(int index, Object element) { getList().add(index, element); reposition(element); } public boolean addAll(Collection c) { boolean b = getList().addAll(c); reposition(); return b; } public boolean addAll(int index, Collection c) { boolean b = getList().addAll(index, c); reposition(); return b; } public Object set(int index, Object element) { Object oldObj = getList().get(index); moveTo(index); setObject(element); return oldObj; } // ============================= public Object get(int index) { return getList().get(index); } public int indexOf(Object o) { return getList().indexOf(o); } public int lastIndexOf(Object o) { return getList().lastIndexOf(o); } public ListIterator listIterator() { return getList().listIterator(); } public ListIterator listIterator(int index) { return getList().listIterator(index); } public List subList(int fromIndex, int toIndex) { return getList().subList(fromIndex, toIndex); } }